using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using LDNS.SDK.IPC;
using LDNS.SDK.Utilities;
using LDNS.Interfaces;
using LDNS.Models;
using LDNS.Services;
using NLog;
using NLog.Config;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.DependencyInjection;
using LDNS.SDK.Commands.Models;


namespace LDNS
{
    /// <summary>
    /// DNS服务命令行选项类
    /// <author>huobing</author>
    /// </summary>
    public class DnsServiceOptions
    {
        public int Port { get; set; } = 0; // 设置为0表示不使用默认值，只有明确提供-p参数时才生效
        public bool IsPortSpecified { get; set; } = false; // 标记是否明确指定了端口参数
        public List<string> UpstreamDnsServers { get; set; } = [];
        public Dictionary<string, DnsRecord> DnsRecords { get; set; } = [];
        public string? ConfigFile { get; set; }
        public bool IsCommand { get; set; } = false; // 标记是否在命令模式下运行
        public bool IsService { get; set; } = false; // 标记是否在服务模式下运行
        public bool RunInBackground { get; set; } = false; // 标记是否在后台运行（隐藏控制台窗口）
        public string[] CommandArgs { get; internal set; } = []; // 命令行参数
    }



    public static class Program
    {
        private const string ServiceMutexName = "LDNS.Main.Service"; // 应用程序唯一标识符

        /// <summary>
        /// 初始化NLog配置
        /// 作者：huobing
        /// </summary>
        private static void InitializeNLog()
        {
            try
            {
                // 根据程序基目录设置日志目录
                // 如果不是在C:\Program Files\LDNS目录下运行，则设置LDNS_DIR环境变量
                string programFilesLdnsPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "LDNS");
                if (!string.Equals(AppContext.BaseDirectory.TrimEnd('\\'), programFilesLdnsPath, StringComparison.OrdinalIgnoreCase))
                {
                    // 非标准安装目录，设置LDNS_DIR环境变量
                    Environment.SetEnvironmentVariable("LDNS_DIR", AppContext.BaseDirectory);
                }
                
                // 获取主程序专用的NLog配置文件路径
                string configFilePath = Path.Combine(AppContext.BaseDirectory, "LDNS.Nlog.config");
                
                // 诊断输出
                if (File.Exists(configFilePath))
                {
                    // 使用XmlLoggingConfiguration加载指定的配置文件
                    LogManager.Configuration = new XmlLoggingConfiguration(configFilePath);
                    // 重新加载配置以应用环境变量设置
                    LogManager.ReconfigExistingLoggers();
                    
                    // 测试日志记录
                    var logger = LogManager.GetCurrentClassLogger();
                    logger.Debug($"[LDNS] NLog配置加载成功，配置文件路径: {configFilePath}");
                    logger.Debug("[LDNS] NLog初始化成功");
                }
                else
                {
                    Console.WriteLine($"[LDNS] NLog配置文件路径: {configFilePath}");
                    Console.WriteLine("[LDNS] 警告: LDNS.Nlog.config配置文件不存在，使用默认配置");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[LDNS] NLog初始化失败: {ex.Message}");
            }
        }
        
        /// <summary>
        /// 输出程序基目录
        /// 作者：huobing
        /// </summary>
        private static void PrintBaseDirectory()
        {
            var baseDir = AppContext.BaseDirectory;
            try
            {
                // 记录到日志（如 NLog 已初始化将写入日志目标）
                var logger = LogManager.GetCurrentClassLogger();
                logger.Debug($"BaseDirectory: {baseDir}");
            }
            catch {
                Console.WriteLine($"[LDNS] BaseDirectory: 日志未就绪时忽略");
            }
        }

        public static int Main(string[]? args)
        {
            try
            { 
                // 解析命令行选项
                var options = ParseServerOptions(args);

                // 只在非服务模式下设置控制台标题
                if (!options.IsService)
                {
                    Console.Title = "LDNS";
                    // 确保控制台使用 UTF-8
                    Console.OutputEncoding = System.Text.Encoding.UTF8;
                    Console.InputEncoding = System.Text.Encoding.UTF8;
                }

                // 检查是否需要管理员权限
                bool needsAdminPrivileges = !options.IsService && !options.IsCommand;
                
                // 对于命令模式，只对特定命令要求管理员权限
                if (options.IsCommand && options.CommandArgs.Length > 0)
                {
                    string command = options.CommandArgs[0].ToUpper();
                    needsAdminPrivileges = command == "START" || command == "STOP" || command == "RESTART";
                }

                // 检查是否以管理员权限运行
                if (needsAdminPrivileges && !PlatformHelper.IsRunAsAdministrator())
                {
                    // 不是以管理员权限运行，提示用户并尝试以管理员权限重启
                    Console.WriteLine("[信息] LDNS需要管理员权限才能正常运行DNS服务或执行特定命令");
                    Console.WriteLine("[信息] 正在尝试以管理员权限重启程序...");
                    
                    // 尝试以管理员权限重启程序
                    if (PlatformHelper.RunAsAdministrator())
                    {
                        // 成功启动了管理员权限的进程，当前进程可以退出
                        return 0;
                    }
                    else
                    {
                        // 提权失败，退出程序
                        Console.WriteLine("[错误] 无法获取管理员权限，程序将退出");
                        if (!options.RunInBackground)
                        {
                            Console.WriteLine("按任意键退出...");
                            Console.ReadKey();
                        }
                        return 1;
                    }
                }
                
                // 如果需要在后台运行，则隐藏控制台窗口
                if (options.RunInBackground && !options.IsService)
                {
                    // 隐藏控制台窗口
                    ConsoleHelper.HideConsoleWindow();
                }

                // 检查是否是命令模式运行（通过IPC执行命令）
                if (options.IsCommand)
                {
                    // 命令模式：使用NamedPipeClient执行命令
                    return RunCommandMode(options.CommandArgs);
                }
                
                // 使用互斥锁确保只有一个实例在运行
                bool mutexCreated = false;
                try
                {
                    // 尝试创建或打开命名互斥锁
                    using (var mutex = new Mutex(true, ServiceMutexName, out mutexCreated))
                    {
                        if (!mutexCreated)
                        {
                            if (options.IsService)
                            {
                                return 1;
                            }
                            // 已有实例在运行，输出提示信息并退出
                            if (!options.RunInBackground)
                            {
                                // 这里使用Console，因为是给用户的直接提示
                                Console.WriteLine("错误：DNS服务已经在运行中！");
                                Console.WriteLine("请先停止现有服务后再启动。");
                                Console.WriteLine("按任意键退出...");
                                Console.ReadKey();
                            }
                            return 1;
                        }

                        // 统一设置工作目录为程序安装目录，避免服务模式下相对路径解析到C:\Windows\System32
                        Directory.SetCurrentDirectory(AppContext.BaseDirectory);
                        
                        // 启动前确保 ProgramData 日志目录存在
                        EnsureLogsDirectory();
                        
                        // 初始化NLog配置，指定主程序专用配置文件
                        InitializeNLog();
                        
                        // 启动时打印 basedir，帮助定位不同运行路径的日志输出目录
                        PrintBaseDirectory();
                        // 服务模式：通过 --service 参数在 Windows 服务托管下运行
                        if (options.IsService)
                        {
                            var host = Host.CreateDefaultBuilder(args)
                                .UseWindowsService() // 将应用托管为 Windows 服务
                                .ConfigureServices(services =>
                                {
                                    // 注入核心服务与启动选项
                                    services.AddSingleton<DnsServiceManager>();
                                    services.AddSingleton(sp => options);
                                    services.AddHostedService<LDNS.Services.WindowsDnsHostedService>();
                                })
                                .Build();

                            host.Run();
                            return 0;
                        }

                        // 始终以服务模式运行
                        var manager = new DnsServiceManager();
                        var ok = manager.Run(options);
                        return ok ? 0 : 1;
                    }
                }
                catch (UnauthorizedAccessException)
                {
                    // 处理权限异常，这通常发生在尝试打开另一个用户创建的互斥锁时
                    try
                    {
                        // 尝试直接检查进程是否存在
                        var processes = System.Diagnostics.Process.GetProcessesByName("LDNS");
                        if (processes.Length > 1)
                        {
                            // 找到多个进程实例
                            if (!options.RunInBackground)
                            {
                                Console.WriteLine("错误：DNS服务已经在运行中！");
                                Console.WriteLine("请先停止现有服务后再启动。");
                                Console.WriteLine("按任意键退出...");
                                Console.ReadKey();
                            }
                            return 1;
                        }
                    }
                    catch (Exception)
                    {
                        // 如果进程检查也失败，就直接报告错误
                        if (!options.RunInBackground)
                        {
                            Console.WriteLine("错误：无法确认服务状态。请检查是否有其他LDNS实例正在运行。");
                            Console.WriteLine("按任意键退出...");
                            Console.ReadKey();
                        }
                    }
                    return 1;
                }
            }
            catch (Exception ex)
            {
                // 使用Console，因为这是程序入口点的致命错误
                Console.Error.WriteLine($"Fatal error: {ex.Message}");
                return 1;
            }
        }

        /// <param name="commandArgs">命令参数</param>
        /// <returns>执行结果状态码</returns>
        private static int RunCommandMode(string[] commandArgs)
        {
            try
            {
                // 构建完整的命令字符串
                string commandLine = string.Join(" ", commandArgs);
                if (string.IsNullOrWhiteSpace(commandLine))
                {
                    Console.Error.WriteLine("错误：未提供命令内容");
                    return 1;
                }

                // 检查是否是需要管理员权限的命令
                string command = commandArgs[0].ToUpper();
                if (command == "REGISTRY_DELETE")
                {
                    if (!PlatformHelper.IsRunAsAdministrator())
                    {
                        Console.WriteLine("[警告] 执行REGISTRY_DELETE命令需要管理员权限！");
                    }
                    else
                    {
                        Console.WriteLine("[信息] 以管理员权限执行REGISTRY_DELETE命令");
                    }
                }

                // 创建IPC客户端并执行命令
                var client = new NamedPipeClient();
                BaseCommandResult result = Task.Run(async () => 
                {
                    return await client.ExecuteCommandAsync(commandLine);
                }).Result;
                // 输出结果
                Console.WriteLine($"{result.ToConsoleString()}");
                return result.Success ? 0 : 1;
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine($"执行命令时出错: {ex.Message}");
                Console.Error.WriteLine($"错误详情: {ex.StackTrace}");
                return 1;
            }
        }

        /// <summary>
        /// 创建Windows服务主机构建器
        /// </summary>
        /// <param name="args">命令行参数</param>
        /// <returns>主机构建器</returns>
        // Windows服务相关功能已移除

        /// <summary>
        /// 显示程序版本信息
        /// 作者：huobing
        /// </summary>
        private static void ShowVersion()
        {
            var assembly = System.Reflection.Assembly.GetExecutingAssembly();
            var version = assembly.GetName().Version;
            Console.WriteLine($"LDNS (Local DNS Service) v{version}");
            Console.WriteLine("本地DNS服务，用于管理DNS解析和缓存");
        }

        /// <summary>
        /// 显示帮助信息
        /// 作者：huobing
        /// </summary>
        private static void ShowHelp()
        {
            ShowVersion();
            Console.WriteLine();
            Console.WriteLine("使用方法：");
            Console.WriteLine("  LDNS [选项]");
            Console.WriteLine();
            Console.WriteLine("选项：");
            Console.WriteLine("  -h, --help               显示此帮助信息并退出");
            Console.WriteLine("  -v, --version            显示版本信息并退出");
            Console.WriteLine("  -p, --port <端口号>       指定DNS服务监听端口（默认：53）");
            Console.WriteLine("  -c, --command <命令>      以命令模式运行，通过IPC执行命令");
            Console.WriteLine("  -s, --service            以Windows服务模式运行");
            Console.WriteLine("  -b, --background         在后台运行（隐藏控制台窗口）");
            Console.WriteLine();
            Console.WriteLine("内部命令帮助：");
            Console.WriteLine("  使用 --command help 查看所有可用的内部命令");
            Console.WriteLine("  使用 --command help <命令名> 查看特定命令的详细信息");
            Console.WriteLine();
            Console.WriteLine("示例：");
            Console.WriteLine("  LDNS                     启动DNS服务（默认端口53）");
            Console.WriteLine("  LDNS --port 5353         启动DNS服务（指定端口5353）");
            Console.WriteLine("  LDNS --command status    执行status命令");
            Console.WriteLine("  LDNS --command help      查看内部命令列表");
            Console.WriteLine("  LDNS --command help add  查看add命令的详细用法");
            Console.WriteLine("  LDNS --background        在后台启动DNS服务");
        }

        private static DnsServiceOptions ParseServerOptions(string[]? args)
        {
            var options = new DnsServiceOptions();
            if (args == null || args.Length == 0) return options;
            for (int i = 0; i < args.Length; i++)
            {
                var a = args[i];
                if (string.Equals(a, "-h", StringComparison.OrdinalIgnoreCase) || string.Equals(a, "--help", StringComparison.OrdinalIgnoreCase))
                {
                    ShowHelp();
                    Environment.Exit(0);
                }
                else if (string.Equals(a, "-v", StringComparison.OrdinalIgnoreCase) || string.Equals(a, "--version", StringComparison.OrdinalIgnoreCase))
                {
                    ShowVersion();
                    Environment.Exit(0);
                }
                else if (string.Equals(a, "-p", StringComparison.OrdinalIgnoreCase) || string.Equals(a, "--port", StringComparison.OrdinalIgnoreCase))
                {
                    if (i + 1 < args.Length && int.TryParse(args[i + 1], out var port) && port > 0 && port <= 65535)
                    {
                        options.Port = port;
                        options.IsPortSpecified = true;
                        i++;
                    }
                }
                else if (string.Equals(a, "-c", StringComparison.OrdinalIgnoreCase) || string.Equals(a, "--command", StringComparison.OrdinalIgnoreCase))
                {
                    options.IsCommand = true;
                    // 确保命令参数数量足够
                    if (i + 1 >= args.Length)
                    {
                        return options;
                    }
                    options.CommandArgs = args.Skip(i + 1).ToArray();
                    break;
                }
                else if (string.Equals(a, "-s", StringComparison.OrdinalIgnoreCase) || string.Equals(a, "--service", StringComparison.OrdinalIgnoreCase))
                {
                    options.IsService = true;
                    break;
                }
                else if (string.Equals(a, "-b", StringComparison.OrdinalIgnoreCase) || string.Equals(a, "--background", StringComparison.OrdinalIgnoreCase))
                {
                    options.RunInBackground = true;
                }
            }
            return options;
        }
        /// <summary>
        /// 确保 ProgramData 日志目录存在（C:\ProgramData\LDNS\logs 与 archive），避免非管理员下写日志失败
        /// 作者：huobing
        /// </summary>
        private static void EnsureLogsDirectory()
        {
            try
            {
                var commonData = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
                var logsRoot = Path.Combine(commonData, "LDNS", "logs");
                var archive = Path.Combine(logsRoot, "archive");
                Directory.CreateDirectory(logsRoot);
                Directory.CreateDirectory(archive);
            }
            catch (UnauthorizedAccessException ex)
            {
                try
                {
                    var logger = LogManager.GetCurrentClassLogger();
                    logger.Warn($"创建 ProgramData 日志目录失败（权限）：{ex.Message}");
                }
                catch { }
            }
            catch (Exception ex)
            {
                try
                {
                    var logger = LogManager.GetCurrentClassLogger();
                    logger.Warn($"创建 ProgramData 日志目录失败：{ex.Message}");
                }
                catch { }
            }
        }
    }
}



